using System;
using System.Collections.Generic;
using System.Text;
using Petra.Gis;
using Petra.Gis.Geometry;
using Petra.Gis.Geometry.Support;
using System.IO;

namespace Petra.Gis.DataServices.GDO
{
  public unsafe partial class GeometryFactory
  {
    /***********************************************
    * 28.8.2007
    * 
    * creates GeometryCollection
    * from intergraph blob structure
    * 
    * asida@centrum.cz, initial implementation
    *************************************************/
    private static GeometryBase binaryToGeometryCollection(byte[] vData, int arrayOffset, System.Type parentGeomType)
    {

      /*Guid ingrGUID;
      fixed (byte* bGUID = &vData[arrayOffset])
      {
        ingrGUID = (*((Guid*)bGUID));
      }
      if (ingrGUID == getGuid[GeometryType.Boundary]) { }*/

      GeometryCollection oGeom = new GeometryCollection();

      int pos;
      fixed (byte* bPtr = &vData[arrayOffset])
      {
        int* lGeomSize;
        GeometryBase tmpGeom;

        //skip position 0, 16 bytes Collection GUID
        //get num of geoms in collection position 16
        pos = 16;
        int* numGeoms = (Int32*)(bPtr + pos);

        //step over all holes
        //set pos to binary size of first geom
        pos += 4;
        for (int i = 0; i < *numGeoms; i++)
        {
          lGeomSize = (Int32*)(bPtr + pos);
          tmpGeom = createGeometry(vData, (arrayOffset + pos + 4), typeof(GeometryCollection));
          oGeom.Add(tmpGeom);
          pos = pos + 4 + *lGeomSize;
        }
      }
      //try if collection contains single type of geometry
      //if yes then convert into specific collection MultiPoint, MultiLabel, MultiLine, MultiArea
      System.Type gt;
      bool bMultiPoint = false;
      bool bMultiLine = false;
      bool bMultiLabel = false;
      bool bMultiArea = false;

      foreach (GeometryBase g in oGeom)
      {
        gt = g.GetType();
        if (gt == typeof(Point))
          bMultiPoint = true;
        if (gt == typeof(Label))
          bMultiLabel = true;
        if (gt == typeof(Arc) || gt == typeof(LineString) || gt == typeof(Geometry.Path))
          bMultiLine = true;
        if (gt == typeof(LineRing) || gt == typeof(Polygon) || gt == typeof(PathRing))
          bMultiArea = true;
      }

      //lookup MultiPoint
      if (bMultiPoint && !(bMultiLabel || bMultiLine || bMultiArea))
      {
        MultiPoint outgeom = new MultiPoint();
        foreach (GeometryBase g in oGeom)
          outgeom.Add(g);
        return outgeom;
      }

      //lookup MultiLabel
      if (bMultiLabel && !(bMultiPoint || bMultiLine || bMultiArea))
      {
        MultiLabel outgeom = new MultiLabel();
        foreach (GeometryBase g in oGeom)
          outgeom.Add(g);
        return outgeom;
      }

      //lookup MultiLine
      if (bMultiLine && !(bMultiPoint || bMultiLabel || bMultiArea))
      {
        MultiLine outgeom = new MultiLine();
        foreach (GeometryBase g in oGeom)
          outgeom.Add(g);
        return outgeom;
      }

      //lookup MultiArea
      if (bMultiArea && !(bMultiPoint || bMultiLabel || bMultiLine))
      {
        MultiArea outgeom = new MultiArea();
        foreach (GeometryBase g in oGeom)
          outgeom.Add(g);
        return outgeom;
      }

      return oGeom;
    }






    /***********************************************
    * 28.8.2007
    * 
    * creates intergraph blob structure 
    * from GeometryCollection
    * 
    * asida@centrum.cz, initial implementation
    *************************************************/
    /// <summary>
    /// creates intergraph GDO blob structure from GeometryCollection
    /// </summary>
    /// <param name="geometry">geometry object</param>
    /// <returns>byte[]</returns>
    private static byte[] geometryCollectionToBinary(GeometryBase geometry)
    {
      //cast to Polygon first
      GeometryCollection _coll = (GeometryCollection)geometry;

      //if only one element in colection skip collection header
      /*if (_coll.Count == 1)
        return saveGeometryBlob(_coll[0]);*/

      int lBlobSize;
      Guid gGeomGUID;

      lBlobSize = 0;

      System.IO.MemoryStream oIMStream = new System.IO.MemoryStream(lBlobSize);
      System.IO.BinaryWriter mBWriter = new System.IO.BinaryWriter(oIMStream);

      oIMStream.Position = 0;
      //write GUID
      gGeomGUID = getGuid[GeometryType.Collection];
      mBWriter.Write(gGeomGUID.ToByteArray());

      mBWriter.Write(collectionItemsToBinary(_coll, 0));
      return oIMStream.ToArray();
    }






    /// <summary>
    /// collectionItemsToBinary returns collection as byte[] WITHOUT GUID.
    /// this method is only for Path and PathRing geometry.
    /// input geometry collection is taken from startIndex to  and converted to binary GDO blob.
    /// startIndex is first element to process
    /// </summary>
    private static byte[] collectionItemsToBinary(GeometryCollection items, int startIndex)
    {

      /*
      if(startIndex >= items.Count || startIndex < 0)
        throw new ArgumentException("Index out of range collectionItemsToBinary()";
      */

      MemoryStream oIMStream = new MemoryStream();
      BinaryWriter mBWriter = new BinaryWriter(oIMStream);

      //write num of items - skipped items (startIndex begins w/ 0)
      mBWriter.Write((Int32)(items.Count - startIndex));

      byte[] tmp;
      for (int i = startIndex; i < items.Count; i++)
      {
        tmp = saveGeometryBlob(items[i]);
        mBWriter.Write((Int32)tmp.Length);
        mBWriter.Write(tmp);
      }
      return oIMStream.ToArray();
    }



  }
}
